#pragma once

#include "Socket.hpp"
#include "TcpServer.hpp"
#include <iostream>
#include <string>
#include <memory>
#include "Util.hpp"
#include <sstream>
#include <unordered_map>
#include "Log.hpp"

using namespace SocketModule;
using namespace LogModule;

const std::string gspace = "  ";
const std::string glinespace = "\r\n";
const std::string glinesep = ": ";

const std::string webroot = "./wwwroot";
const std::string homepage = "index.html";
const std::string page_404 = "/404.html";

class HttpRequest
{
public:
    HttpRequest() : _is_interact(false)
    {
    }

    std::string Serialize()
    {
        return "";
    }

    void PaseReqLine(std::string &reqline)
    {
        // GET / HTTP/1.1
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
    }

    bool Deserialize(std::string &reqstr)
    {
        // 1. 以换行符作为分隔符，读取请求行
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, glinespace);
        LOG(LogLevel::DEBUG) << "reqline: " << reqline;

        // 2. 对请求行进行反序列化
        // GET / HTTP/1.1
        PaseReqLine(reqline);
        if (_uri == "/")
            _uri = webroot + _uri + homepage;
        else
            _uri = webroot + _uri;

        if (_method == "POST")
        {
            _is_interact = true;
            // 3. 读取请求报头
            while (Util::ReadOneLine(reqstr, &reqline, glinespace))
            {
                if (reqline.empty())
                    break;
                size_t pos = reqline.find(glinesep);
                if (pos == std::string::npos)
                {
                    //...
                    LOG(LogLevel::ERROR) << "请求报头格式错误";
                    return false;
                }
                std::string key = reqline.substr(0, pos);
                std::string value = reqline.substr(pos + glinesep.length());
                _headers.insert(std::make_pair(key, value));
            }

            // 4. 读取请求正文
            if (_headers.find("Content-Length") != _headers.end())
            {
                int content_length = std::stoi(_headers["Content-Length"]);
                _text = reqstr.substr(0, content_length);
                reqstr.erase(0, content_length);
            }
        }

        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _version;

        // 0.0.0.0:8080/login?username=zhangsan&password=123456
        const std::string temp = "?";
        auto pos = _uri.find(temp);
        if (pos != std::string::npos)
        {
            _args = _uri.substr(pos + temp.size());
            _uri = _uri.substr(0, pos);
            _is_interact = true;
        }

        return true;
    }

    std::string Uri() { return _uri; }
    bool isInteract() { return _is_interact; }
    std::string Args() { return _args; }
    ~HttpRequest()
    {
    }

private:
    std::string _method;
    std::string _uri;
    std::string _version;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    std::string _args; // 查询参数
    bool _is_interact; // 是否交互模式
};

class HttpResponse
{
public:
    HttpResponse() : _blankline(glinespace), _version("HTTP/1.1")
    {
    }

    std::string Serialize()
    {
        std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace; // 状态行
        std::string resp_header;                                                                           // 响应报头
        for (auto &header : _headers)
        {
            std::string line = header.first + glinesep + header.second + glinespace;
            resp_header += line;
        }

        return status_line + resp_header + glinespace + _text; // 状态行 + 响应报头 + 空行 + 响应正文
    }

    bool Deserialize(std::string &reqstr)
    {

        return true;
    }

    void SetTargetFile(const std::string &target)
    {
        _targetfile = target;
    }

    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        case 302:
            _desc = "Found";
            break;
        case 301:
            _desc = "Moved Permanently";
            break;
        default:
            _desc = "Unknown";
            break;
        }
    }

    void SetHeader(const std::string &key, const std::string &value)
    {
        auto iter = _headers.find(key);
        if (iter != _headers.end())
            return;
        _headers.insert(std::make_pair(key, value));
    }

    std::string Uri2Suffix(const std::string &targetfile)
    {
        auto pos = targetfile.rfind('.');
        if (pos == std::string::npos)
        {
            return "text/html";
        }

        std::string suffix = targetfile.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
        {
            return "text/html";
        }
        else if (suffix == ".jpg")
        {
            return "image/jpeg";
        }
        else if (suffix == ".png")
        {
            return "image/png";
        }
        else if (suffix == ".gif")
        {
            return "image/gif";
        }
        else if (suffix == ".css")
        {
            return "text/css";
        }
        else if (suffix == ".js")
        {
            return "application/javascript";
        }
        else if (suffix == ".json")
        {
            return "application/json";
        }
        else if (suffix == ".xml")
        {
            return "text/xml";
        }
        else if (suffix == ".txt")
        {
            return "text/plain";
        }
        else
        {
            return "text/html";
        }
    }

    bool MakeResponse()
    {
        if (_targetfile == "./wwwroot/favicon.ico")
        {
            LOG(LogLevel::DEBUG) << "用户请求: " << _targetfile << "忽略它";
            return false;
        }
        if (_targetfile == "./wwwroot/redir_test") // 重定向测试
        {
            SetCode(302);
            SetHeader("Location", "https://www.dbhsgxh.com:2087/vod/detail/11148027.html?v=3948");
            return true;
        }
        int filesize = 0;
        bool res = Util::ReadFileContent(_targetfile, &_text);
        if (!res)
        {
            // _text = "";
            // SetCode(404);
            // _targetfile = webroot + page_404;
            // filesize = Util::FileSize(_targetfile);
            // Util::ReadFileContent(_targetfile, &_text);
            // std::string suffix = Uri2Suffix(_targetfile);
            // SetHeader("Content-Type", suffix);
            // SetHeader("Content-Length", std::to_string(filesize));
            SetCode(302);
            SetHeader("Location", "https://www.dbhsgxh.com:2087/vod/detail/11148027.html?v=3948");
        }
        else
        {
            LOG(LogLevel::DEBUG) << "读取文件：" << _targetfile;
            SetCode(200);
            filesize = Util::FileSize(_targetfile);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeader("Content-Type", suffix);
            SetHeader("Content-Length", std::to_string(filesize));
        }
        return true;
    }

    void SetText(const std::string &text)
    {
        _text = text;
    }

    ~HttpResponse() {}

public:
    std::string _version;
    int _code;
    std::string _desc;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    std::string _targetfile;
};

using http_func_t = std::function<void(HttpRequest &req, HttpResponse &resp)>;

class Http
{
public:
    Http(uint16_t port) : tsvrp(std::make_unique<TcpServer>(port))
    {
    }

    void HandlerHttpRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        // #ifndef DEBUG
        // #define DEBUG
        // 接收HTTP请求
        std::string httpreqstr;
        HttpResponse resp; // 一个应答
        int n = sock->Recv(&httpreqstr);
        if (n > 0)
        {
            HttpRequest req;             // 一个请求
            req.Deserialize(httpreqstr); // 请求反序列化，将uri解析为文件路径
            if (req.isInteract())        // 交互模式
            {
                if (_route.find(req.Uri()) == _route.end())
                {
                }
                else // 有注册的服务
                {
                    _route[req.Uri()](req, resp);
                    std::string response_str = resp.Serialize(); // 应答序列化
                    sock->Send(response_str);                    // 发送应答
                }
            }
            else
            {
                resp.SetTargetFile(req.Uri());
                if (resp.MakeResponse()) // 根据uri生成响应报文
                {
                    std::string response_str = resp.Serialize(); // 应答序列化
                    sock->Send(response_str);                    // 发送应答
                }
            }

            // std::string filename = req.Uri();
            // HttpResponse resp;
            // resp._version = "HTTP/1.1";
            // resp._code = 200;
            // resp._desc = "OK";

            // // LOG(LogLevel::DEBUG) << "用户请求：" << filename;
            // bool res = Util::ReadFileContent(filename, &(resp._text)); // 读取文件内容
            // (void)res;
        }

#ifdef DEBUG
        std::string httpreqstr;
        sock->Recv(&httpreqstr);
        std::cout << httpreqstr << std::endl;

        //
        HttpResponse resp;
        resp._version = "HTTP/1.1";
        resp._code = 200;
        resp._desc = "OK";

        std::string filename = webroot + homepage; // "./wwwroot/index.html" web根目录
        bool res = Util::ReadFileContent(filename, &(resp._text));
        (void)res;

        std::string response_str = resp.Serialize();
        sock->Send(response_str);
#endif
    }

    void Start()
    {
        tsvrp->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client)
                     { this->HandlerHttpRequest(sock, client); });
    }

    void RegisterService(std::string name, http_func_t h)
    {
        name = webroot + name;
        auto iter = _route.find(name);
        if (iter == _route.end())
        {
            _route.insert(std::make_pair(name, h));
        }
    }

    ~Http()
    {
    }

private:
    std::unique_ptr<TcpServer> tsvrp;
    std::unordered_map<std::string, http_func_t> _route;
};